package fen_su

import (
	"device-modbus/core"
	"device-modbus/internal/biz/model"
	"encoding/binary"
	"errors"
	"fmt"
	"time"

	"github.com/cloudwego/hertz/pkg/common/hlog"
)

// 气象传感器 - 铝壳风速传感器（485型，ZTS-3000-FSA-N01）

// WindSensorData 解析后的风速传感器数据
type WindSensorData struct {
	DeviceAddr    byte    // 设备地址（1-254，默认0x01）
	FuncCode      byte    // 功能码（读：0x03；写：0x06）
	ValidBytes    byte    // 应答帧有效数据字节数
	InstantWind   float64 // 瞬时风速（单位：m/s，分辨率0.1m/s）
	WindLevelName string  // 瞬时风速等级名称
	WindLevel     int     // 瞬时风速等级
	BaudRate      uint16  // 设备波特率（对应值：0=2400,1=4800<默认>,2=9600...7=1200）
	NewDeviceAddr uint16  // 新设备地址（仅修改地址时使用，1-254）
}

// FenSu 风速传感器协议实现
type FenSu struct{}

// NewProtocol 创建新的风速传感器协议实例
func NewProtocol() core.SensorProtocol {
	return &FenSu{}
}

// GetType 返回传感器类型
func (p *FenSu) GetType() string {
	return "modbus" // 风速传感器类型标识
}

// GetModel 返回传感器型号
func (p *FenSu) GetModel() string {
	return "fen_su" // 示例风速传感器型号
}

// GetProtocolName 返回协议名称
func (p *FenSu) GetProtocolName() string {
	return "风速" // 唯一协议名称
}

// BuildRequest 构建风速传感器请求帧（支持读风速、改地址、改波特率）
func (p *FenSu) BuildRequest(deviceAddr, funcCode byte, startAddr, dataLength uint16) ([]byte, error) {
	// 校验参数合法性（基于传感器手册定义）
	if deviceAddr < 0x01 || deviceAddr > 0xFE {
		return nil, errors.New("设备地址非法，需在1-254范围内")
	}
	if funcCode != 0x03 && funcCode != 0x06 {
		return nil, errors.New("仅支持功能码0x03（读）和0x06（写）")
	}
	// 校验寄存器地址（仅支持手册中定义的关键寄存器）
	validStartAddrs := map[uint16]bool{0x0000: true, 0x07D0: true, 0x07D1: true}
	if !validStartAddrs[startAddr] {
		return nil, fmt.Errorf("起始寄存器地址非法，仅支持0x0000(风速)、0x07D0(地址)、0x07D1(波特率)")
	}
	// 打印请求帧日志
	hlog.Debugf("构建风速传感器请求帧: 设备地址=0x%02X, 功能码=0x%02X, 起始寄存器=0x%04X, 数据长度/值=0x%04X",
		deviceAddr, funcCode, startAddr, dataLength)

	// 构建帧主体（6字节：地址码+功能码+起始地址(2字节)+数据长度/值(2字节)）
	frame := make([]byte, 6)
	frame[0] = deviceAddr
	frame[1] = funcCode
	binary.BigEndian.PutUint16(frame[2:4], startAddr)  // 寄存器地址高位在前
	binary.BigEndian.PutUint16(frame[4:6], dataLength) // 读：寄存器数量；写：参数值

	// 计算并添加CRC16校验码（低位在前，高位在后）
	crc := calculateWindCRC(frame)
	frame = append(frame, byte(crc&0xFF))    // CRC低字节
	frame = append(frame, byte(crc>>8&0xFF)) // CRC高字节

	return frame, nil
}

// ParseResponse 解析风速传感器应答帧（支持读风速、写参数确认）
func (p *FenSu) ParseResponse(response []byte) (*model.SensorData, error) {
	// 1. 基础长度校验（最小长度：读应答7字节，写应答8字节）
	if len(response) < 7 {
		return nil, errors.New("应答帧长度不足，最小需7字节")
	}
	// 2. 提取帧头信息
	deviceAddr := response[0]
	funcCode := response[1]
	if response[0] != 0x04 {
		return nil, fmt.Errorf("%w: 设备地址应为0x04，实际0x%02X", core.ErrorInvalidResponse, response[0])
	}
	// 3. 错误功能码检查（功能码最高位为1表示设备返回错误）
	if (funcCode & 0x80) != 0 {
		return nil, fmt.Errorf("设备返回错误，错误功能码=0x%02X", funcCode)
	}
	// 4. CRC校验（校验范围：除最后2字节CRC外的所有数据）
	dataPart := response[:len(response)-2]
	receivedCRC := binary.LittleEndian.Uint16(response[len(response)-2:]) // 接收的CRC（低位在前）
	calculatedCRC := calculateWindCRC(dataPart)
	if receivedCRC != calculatedCRC {
		return nil, fmt.Errorf("CRC校验失败，接收CRC=0x%04X，计算CRC=0x%04X", receivedCRC, calculatedCRC)
	}

	// 5. 按功能码分场景解析数据
	result := &WindSensorData{
		DeviceAddr: deviceAddr,
		FuncCode:   funcCode,
	}

	// 场景1：功能码0x03（读取风速数据，应答帧7字节：地址+功能码+有效字节数+风速(2字节)+CRC(2字节)）
	// 有效字节数校验（读1个寄存器需返回2字节数据，故有效字节数=0x02）
	validBytes := response[2]
	if validBytes != 0x02 {
		return nil, fmt.Errorf("读风速应答有效字节数异常，期望0x02，实际0x%02X", validBytes)
	}
	result.ValidBytes = validBytes

	// 解析瞬时风速（寄存器0x0000数据为真实值的10倍，需除以10）
	windRaw := binary.BigEndian.Uint16(response[3:5])
	result.InstantWind = float64(windRaw) / 10.0
	hlog.Debugf("解析风速数据：设备地址=0x%02X，瞬时风速=%.1f m/s", deviceAddr, result.InstantWind)
	// 6. 转换风速等级
	result.WindLevel, result.WindLevelName, _ = result.getWindLevel()
	// 7. 返回解析结果
	return &model.SensorData{
		SensorID:  fmt.Sprintf("fen_su_%02X", deviceAddr),
		Type:      p.GetType(),
		Model:     p.GetModel(),
		Timestamp: time.Now().UnixNano() / int64(time.Millisecond),
		RawData:   response,
		Values: map[string]string{
			"instantWind":   fmt.Sprintf("%.1f", result.InstantWind),
			"windLevel":     fmt.Sprintf("%d", result.WindLevel),
			"windLevelName": result.WindLevelName,
		},
		Protocol: p.GetProtocolName(),
	}, nil
}

// calculateWindCRC 计算ModBus-RTU CRC16校验码（多项式0xA001，低位在前）
// 符合传感器手册中“错误校验采用CRC冗余循环码”的定义
func calculateWindCRC(data []byte) uint16 {
	crc := uint16(0xFFFF) // 初始值
	for _, b := range data {
		crc ^= uint16(b)
		for i := 0; i < 8; i++ {
			if (crc & 0x0001) != 0 { // 检查最低位
				crc >>= 1
				crc ^= 0xA001 // 多项式
			} else {
				crc >>= 1
			}
		}
	}
	return crc
}

// getWindLevel 根据瞬时风速获取风力等级（参考传感器手册“风力等级表”）
func (w *WindSensorData) getWindLevel() (int, string, error) {
	if w.InstantWind < 0 {
		return -1, "", errors.New("风速值非法，不能为负数")
	}

	// 风力等级划分（对应手册中“17级风力等级表”核心区间）
	switch {
	case w.InstantWind <= 0.2:
		return 0, "无风", nil
	case w.InstantWind <= 1.5:
		return 1, "软风", nil
	case w.InstantWind <= 3.3:
		return 2, "软风", nil
	case w.InstantWind <= 5.4:
		return 3, "微风", nil
	case w.InstantWind <= 7.9:
		return 4, "和风", nil
	case w.InstantWind <= 10.7:
		return 5, "清劲风", nil
	case w.InstantWind <= 13.8:
		return 6, "强风", nil
	case w.InstantWind <= 17.1:
		return 7, "疾风", nil
	case w.InstantWind <= 20.7:
		return 8, "大风", nil
	case w.InstantWind <= 24.4:
		return 9, "烈风", nil
	case w.InstantWind <= 28.4:
		return 10, "狂风", nil
	case w.InstantWind <= 32.6:
		return 11, "暴风", nil
	case w.InstantWind <= 36.9:
		return 12, "飓风", nil
	case w.InstantWind <= 41.4:
		return 13, "飓风", nil
	case w.InstantWind <= 46.1:
		return 14, "飓风", nil
	case w.InstantWind <= 50.9:
		return 15, "飓风", nil
	case w.InstantWind <= 56.0:
		return 16, "飓风", nil
	case w.InstantWind <= 61.2:
		return 17, "飓风", nil
	default:
		return -1, "超量程", nil
	}
}
